package com.suncky.frame.base.adapter;

import android.content.Context;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import retrofit2.Retrofit;

/**
 * 可选列表适配器
 * Created by HY_PC on 2018 11/21 0021 18:42.
 */
public abstract class OptionRecyclerAdapter<T> extends RecyclerViewAdapter<T> implements Optional<T> {
    protected List<T> selectedOptions=new ArrayList<>();
    protected boolean enable = true;//是否启用选择
    private boolean cancelable = true;//是否可取消选择
    private @OptionalType int optionType;

    public OptionRecyclerAdapter(Context context) {
        super(context);
    }

    public OptionRecyclerAdapter(Context context, List<T> data) {
        super(context, data);
    }

    public OptionRecyclerAdapter(Context context, List<T> data, int itemLayoutId) {
        super(context, data, itemLayoutId);
    }

    /**
     *
     * @param context
     * @param data
     * @param itemLayoutId
     * @param optionEnable 是否启用选择
     */
    public OptionRecyclerAdapter(Context context, List<T> data, int itemLayoutId, boolean optionEnable) {
        super(context, data, itemLayoutId);
        this.enable = optionEnable;
    }

    @Override
    public void setOptionType(@OptionalType int optionType) {
        this.optionType = optionType;
    }

    /**
     * option enabled true,otherwise false. default true;
     * @return
     */
    public boolean isEnable() {
        return enable;
    }

    /**
     * set option enable
     * @param enable enable true,otherwise false
     */
    public void setEnable(boolean enable) {
        this.enable = enable;
        clearChoice();
    }

    public List<T> getSelectedOptions() {
        return selectedOptions;
    }

    /**
     * 强行清除已选项
     */
    public void clearChoice(){
        unSelectAll();
    }

    /**
     * 选项变化,更新选项状态
     * @param position
     */
    public void notifySelectChange(int position) {
        notifySelectChange(position, null, null);
    }

    /**
     * 选项变化,更新选项状态
     * @param position 更新选项位置
     * @param payloadSelect 选择的item局部刷新参数
     * @param payloadUnselect 未选择的选择item局部刷新参数
     */
    public void notifySelectChange(int position, @Nullable Object payloadSelect, @Nullable Object payloadUnselect) {
        notifySelectChange(getItem(position), position,payloadSelect,payloadUnselect);
    }

    /**
     * 选项变化,更新选项状态
     * @param o
     */
    public void notifySelectChange(T o) {
        notifySelectChange(o, null, null);
    }

    /**
     * 选项变化,更新选项状态
     * @param o 更新的选项
     * @param payloadSelect 选择的item局部刷新参数
     * @param payloadUnselect 未选择的选择item局部刷新参数
     */
    public void notifySelectChange(T o, @Nullable Object payloadSelect, @Nullable Object payloadUnselect) {
        notifySelectChange(o, mDatas.indexOf(o), payloadSelect, payloadUnselect);
    }

    private void notifySelectChange(T o, int position, @Nullable Object payloadSelect, @Nullable Object payloadUnselect) {
        if (o == null || !isEnable()) {
            return;
        }
        if (isSelected(o)) {
            if (!cancelable) {
                return;
            }
            selectedOptions.remove(o);
        } else {
            if (optionType == TYPE_NOME) {
                return;
            }
            if (optionType == TYPE_SINGLE) {
                if (!selectedOptions.isEmpty()) {
                    T item= selectedOptions.get(0);
                    selectedOptions.remove(item);
                    notifyItemChanged(mDatas.indexOf(item), payloadUnselect);
                }
            }
            selectedOptions.add(o);
        }
        notifyItemChanged(position, payloadSelect);
    }

    /**
     * 选项变化,更新选项状态
     * @param position
     * @deprecated user {@link #notifySelectChange(int)} instead
     */
    public void select(int position) {
        select(getItem(position));
    }

    /**
     * 选项变化,更新选项状态
     * @param o
     * @deprecated 此方法会重新绑定数据,为获得更好的体验,请使用 {@link #notifySelectChange(Object)} 方法
     */
    public void select(T o){
        if (o == null || !isEnable()) {
            return;
        }
        switch (OptionType()) {
            case Optional.TYPE_SINGLE:
                if (!isSelected(o)) {
                    selectedOptions.clear();
                    selectedOptions.add(o);
                }
                break;
            case Optional.TYPE_MULTI:
                if (!isSelected(o)) {
                    selectedOptions.add(o);
                } else {
                    selectedOptions.remove(o);
                }
                break;
            case Optional.TYPE_NOME:
                break;
        }
        notifyDataSetChanged();
    }

    /**
     * 选项变化,更新选项状态
     * @param position
     * @deprecated 此方法会重新绑定数据,为获得更好的体验,请使用 {@link #notifySelectChange(int)} 方法
     */
    public void selectOption(int position) {
        selectOption(getItem(position));
    }

    @Override
    public void selectOption(T item) {

        if (item == null || !isEnable() || isSelected(item)) {
            return;
        }
        if (optionType == Optional.TYPE_SINGLE && !selectedOptions.isEmpty()) {
            T m = selectedOptions.get(0);
            selectedOptions.remove(m);
            notifyItemChanged(mDatas.indexOf(m));
        }
        selectedOptions.add(item);
        notifyItemChanged(mDatas.indexOf(item));
    }

    public void unselectOption(int position) {
        unselectOption(getItem(position));
    }

    @Override
    public void unselectOption(T item) {
        if (item == null || !isEnable() || !isCancelable()) {
            return;
        }
        if (isSelected(item)) {
            selectedOptions.remove(item);
            notifyItemChanged(mDatas.indexOf(item));
        }
    }

    @Override
    public void selectAll(){
        if (isEnable() && OptionType() == Optional.TYPE_MULTI && mDatas != null && !mDatas.isEmpty()) {
            selectedOptions.clear();
            selectedOptions.addAll(mDatas);
            notifyItemRangeChanged(0, getItemCount());
        }
    }

    @Override
    public void unSelectAll() {
        Iterator<T> iterator = selectedOptions.iterator();
        T item;
        while (iterator.hasNext()) {
            item = iterator.next();
            iterator.remove();
            notifyItemChanged(mDatas.indexOf(item));
        }
    }

    @Override
    public void invertSelect() {
        if (!isEnable() || mDatas == null || mDatas.isEmpty() || optionType != TYPE_MULTI) {
            return;
        }
        for (T m : mDatas) {
            if (isSelected(m)) {
                if (!cancelable) {
                    continue;
                }
                selectedOptions.remove(m);
            } else {
                selectedOptions.add(m);
            }
        }
        notifyItemRangeChanged(0, getItemCount());
    }

    @Override
    public boolean isSelected(T object){
        if (object == null) {
            return false;
        }
        return selectedOptions.contains(object);
    }

    @Override
    public void setSelectedOptions(List<T> selectedOptions) {
        if (selectedOptions == null || selectedOptions.isEmpty()) {
            clearChoice();
            return;
        }
        for (T m : selectedOptions) {
            if (!isSelected(m)) {
                selectedOptions.add(m);
                notifyItemChanged(mDatas.indexOf(m));
            }
        }
        for (T m : selectedOptions) {
            if (!selectedOptions.contains(m)) {
                selectedOptions.remove(m);
                notifyItemChanged(mDatas.indexOf(m));
            }
        }
    }

    @Override
    public void addSelectedOptions(List<T> options) {
        if (options == null || options.size() == 0) {
            return;
        }
        for (T m : options) {
            if (!this.selectedOptions.contains(m)) {
                this.selectedOptions.add(m);
                notifyItemChanged(mDatas.indexOf(m));
            }
        }
    }

    @Override
    public int OptionType() {
        return optionType;
    }

    @Override
    public void cancelable(boolean able) {
        this.cancelable = able;
    }

    @Override
    public boolean isCancelable() {
        return this.cancelable;
    }
}
